package com.example.sandbox;

import com.example.pojo.sandbox.ExecuteCodeRequest;
import com.example.pojo.sandbox.ExecuteCodeResponse;
import com.example.pojo.sandbox.ExecuteMessage;
import com.example.utils.FileUtils;
import com.example.utils.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.List;

/**
 * C++语言对应的代码沙箱
 */
@Slf4j
@Component
public class CPlusPlusCodeSandbox implements CodeSandbox {

    // 文件操作工具类
    @Autowired
    private FileUtils fileUtils;
    // 响应结果操作工具类
    @Autowired
    private ResponseUtils responseUtils;
    // C++语言统一类名
    private static final String GLOBAL_CPLUSPLUS_CLASS_NAME = "Main.cpp";
    // 代码最长运行时间
    public static final long TIME_OUT = 10000L;

    // 实现C++语言的编译运行
    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        // 拿到待执行代码
        String code = executeCodeRequest.getCode();
        // 获取输入用例
        List<String> inputList = executeCodeRequest.getInputList();
        // 将用户代码保存为文件
        File userCodeFile = fileUtils.saveCodeToFile(code, GLOBAL_CPLUSPLUS_CLASS_NAME);
        // 获取当前文件路径
        String userCodeFilePath = userCodeFile.getAbsolutePath();
        // 获取去掉文件后缀后的文件路径，此路径作为编译后exe的存放地
        int lastIndex = userCodeFilePath.lastIndexOf(".");
        String compileTo = userCodeFilePath.substring(0, lastIndex);
        // 拼接编译命令
        String compileCmd = String.format("g++ -o %s %s", compileTo, userCodeFilePath);
        log.info("编译命令：{}", compileCmd);
        // 执行编译命令获取编译后信息
        ExecuteMessage compileExecuteMessage = fileUtils.compileCodeFile(compileCmd);
        // 书写运行命令
        String runCmd = String.format(compileTo);
        log.info("运行命令：{}", runCmd);
        // 执行运行命令，并整理得到运行结果
        List<ExecuteMessage> runExecuteMessageList = fileUtils.runCodeFile(runCmd, inputList, TIME_OUT);
        ExecuteCodeResponse outputResponse = responseUtils.getOutputResponse(runExecuteMessageList);
        log.info("运行结果：{}", outputResponse);
        // 清除用户代码文件
        boolean clearFile = fileUtils.clearFile(userCodeFile);
        if (!clearFile) {
            log.info("文件删除失败：" + userCodeFile.getAbsoluteFile());
        }
        return outputResponse;
    }
}
